extends layout

block headContent
	title Node Details
	
block content
	+pageTitle("Node Details")

	if (getblockchaininfo)
		if (false)
			p Data from RPC commands 
				a(href="./rpc-browser?method=getblockchaininfo") getblockchaininfo
				span , 
				a(href="./rpc-browser?method=getnetworkinfo") getnetworkinfo
				span , and 
				a(href="./rpc-browser?method=getnettotals") getnettotals

		if (false)
			pre
				code.json #{JSON.stringify(getblockchaininfo, null, 4)}


		+pageTabs(["Details", "JSON"])


		div.tab-content
			+pageTab("Details", true)

				if (getblockchaininfo.warnings)
					if (Array.isArray(getblockchaininfo.warnings) && getblockchaininfo.warnings.length > 0)
						+contentSection("Active Warnings")
							pre
								code.json(data-lang="json") #{JSON.stringify(getblockchaininfo.warnings, null, 4)}

					else if (typeof getblockchaininfo.warnings === "string" && getblockchaininfo.warnings.trim().length > 0)
						+contentSection("Active Warnings")
							span.text-danger #{getblockchaininfo.warnings}

				+contentSection("Node Summary")
					+summaryRow(4)
						+summaryItem("Version", "Node version number and subversion string")
							| #{getnetworkinfo.version} (#{getnetworkinfo.subversion})

						+summaryItem("Protocol Version", "Protocol version number")
							| #{getnetworkinfo.protocolversion}

						+summaryItem("Status", "Block download progress or synchronized state")
							if (getblockchaininfo.initialblockdownload || getblockchaininfo.headers > getblockchaininfo.blocks)
								span Initial block download progress #{(100 * getblockchaininfo.verificationprogress).toLocaleString()}%
							else
								span.text-success Synchronized

						+summaryItem("Uptime", "How long this node has been running")
							- var startTimeAgo = moment.duration(uptimeSeconds * 1000);
							span #{startTimeAgo.format()}

				+contentSection("Blockchain")
					+summaryRow(4 + (getblockchaininfo.size_on_disk ? 1 : 0) + (getblockchaininfo.pruned ? 1 : 0))
						+summaryItem("Chain", "Network name (main, test, signet, regtest)")
							if (getblockchaininfo.chain == "main")
								span.text-success #{getblockchaininfo.chain}
							else
								span.text-warning #{getblockchaininfo.chain}

						+summaryItem("Block Count", "Current height of the most-work fully-validated chain. Also number of headers this node has validated")
							| #{getblockchaininfo.blocks.toLocaleString()}
							if (getblockchaininfo.headers != getblockchaininfo.blocks)
								br
								small.text-muted (headers: #{getblockchaininfo.headers.toLocaleString()})

						+summaryItem("Difficulty", "Mining difficulty (adjusted every 2016 blocks to maintain the time it takes to process one block at around 10 minutes)")
							- var difficultyData = utils.formatLargeNumber(getblockchaininfo.difficulty, 3);
							span.border-dotted(title=parseFloat(getblockchaininfo.difficulty).toLocaleString(), data-bs-toggle="tooltip")
								span #{difficultyData[0]}
								span  x 10
								sup #{difficultyData[1].exponent}

						if (getblockchaininfo.size_on_disk)
							+summaryItem("Data Size", "Estimated size of the block and undo files on disk")
								- var sizeData = utils.formatLargeNumber(getblockchaininfo.size_on_disk, 1);
								| #{sizeData[0]} #{sizeData[1].abbreviation}B

						if (getblockchaininfo.pruned)
							+summaryItem("Pruned?", "Whether your node prunes the blockchain. With pruning active, your node will delete some data that is non-essential for future verification needs, in order to reduce disk usage.")
								span.text-warning Yes
								small.ms-2.text-muted
									| (
									span.border-dotted(title="This is the latest block for which your node has all block data; blocks older than this one have had some or all non-essential details deleted.", data-bs-toggle="tooltip")
										| #{getblockchaininfo.pruneheight.toLocaleString()}+
									| )
								
								if (false)
									br

									span.border-dotted(title="This is the approximate amount of non-essential blockchain data that your node will store.", data-bs-toggle="tooltip") Prune target size

									span :&nbsp;
										- var pruneTargetSize = utils.formatLargeNumber(getblockchaininfo.prune_target_size, 1);
								
										span #{pruneTargetSize[0]} #{pruneTargetSize[1].abbreviation}B

						+summaryItem("Data Indexes", "Status of available indices currently running in this node")
							ul.list-unstyled.mb-0
								li
									span.me-2 txindex
									if (global.txindexAvailable)
										i.bi-check2.text-success
									else
										span.border-dotted(title="Your node's lack of a 'transaction index' means this explorer will be unable to show all blockchain data. See the project README for more details.", data-bs-toggle="tooltip")
											i.bi-x.text-danger

								li
									span.me-2 coinstatsindex
									if (getindexinfo && getindexinfo["coinstatsindex"])
										i.bi-check2.text-success
									else
										i.bi-x.text-danger

								li
									span.me-2 blockfilterindex
									if (getindexinfo && getindexinfo["basic block filter index"])
										i.bi-check2.text-success
									else
										i.bi-x.text-danger


				if (getdeploymentinfo && getdeploymentinfo.deployments)
					-
						var forkUrls = {
							"bip34":  { "link": "https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki", "title": "Block v2, Height in Coinbase" },
							"bip65":  { "link": "https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki", "title": "OP_CHECKLOCKTIMEVERIFY" },
							"bip66":  { "link": "https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki", "title": "Strict DER signatures" },
							"csv":    { "link": "https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki", "title": "OP_CHECKSEQUENCEVERIFY" },
							"segwit": { "link": "https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki", "title": "Segregated Witness (Consensus layer)" }, 
							"taproot":{ "link": "https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki", "title": "Taproot: SegWit version 1 spending rules" }
						};

					+contentSection("Deployments")
						+summaryRow(utils.objectProperties(getdeploymentinfo.deployments).length)
							each item, itemName in getdeploymentinfo.deployments
								// (title, titleDesc, subtitle, subtitleDesc, linkText, linkUrl)
								+summaryItem(itemName, forkUrls[itemName] ? forkUrls[itemName].title : null)
									if (item.active)
										span.me-2
											span.text-success active
											span.text-tiny.text-muted.ms-2 (
												a.border-dotted(href=`./block-height/${item.height}`, title=`${itemName} has been active since block ${item.height.toLocaleString()}`, data-bs-toggle="tooltip") #{item.height.toLocaleString()}
												| +)

									else
										if (item.type == "bip8") || (item.type == "bip9")
											- var bip = item.type;
											- var bip_status = item[bip].status
											span.me-2
												span.text-warning.text-lowercase #{bip_status}
												small.text-muted.ms-2 (
													a.border-dotted(title=`${itemName.toUpperCase()} ${bip_status.replace("_", " ")} since block ${item[bip].since.toLocaleString()} with BIP${bip.charAt(3)} and LockinOnTimeout=${item[bip].lockinontimeout}`, data-bs-toggle="tooltip") #{item[bip].since}
													| +)

										if (item.type == "bip9" && item.bip9 && (item.bip9.start_time || item.bip9.timeout))
											div.small.text-muted
												if (item.bip9.start_time)
													span.me-2 start:
													+timestamp(item.bip9.start_time, {includeAgo:false, formatString:"M/D"})

												if (item.bip9.timeout)
													if (item.bip9.start_time)
														span.me-1 ,
													span.me-2 timeout:
													+timestamp(item.bip9.timeout, {includeAgo:false, formatString:"M/D"})

										if (item.type == "bip9" && item.bip9 && item.bip9.min_activation_height)
											div.small.text-muted
												span.border-dotted(title="Minimum activation block height", data-bs-toggle="tooltip") min height
												span.me-2 :
												| #{item.bip9.min_activation_height.toLocaleString()}

									if (forkUrls[itemName])
										small
											a(href=forkUrls[itemName].link, title=`More info about ${itemName}`, data-bs-toggle="tooltip", target="_blank")
												i.bi-box-arrow-up-right.small


				// deprecated, as of v23.0, which now has this data in getdeploymentinfo.deployments (see above)
				if (getblockchaininfo.softforks)
					if (getblockchaininfo.bip9_softforks)
						// old format: ~ v0.18.0
						- var softforks = [];
						each item in getblockchaininfo.softforks
							- softforks.push(item);

						each item, itemName in getblockchaininfo.bip9_softforks
							- item.id = itemName
							- softforks.push(item);

						+contentSection("Soft Forks")
							+summaryRow(softforks.length)
								each item in softforks
									+summaryItem(item.id)
										each propVal, propName in item
											if (propName == "reject")
												div reject: #{propVal.status}

											else if (propName == "id")
											else if (propName != "id")
												div #{propName}: #{propVal}

					else
						// more modern format
						- var forkUrls = {"bip34":"https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki", "bip65":"https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki", "bip66":"https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki", "csv":"https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki", "segwit":"https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki", "taproot":"https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki"};

						+contentSection("Soft Forks")
							+summaryRow(utils.objectProperties(getblockchaininfo.softforks).length)
								each item, itemName in getblockchaininfo.softforks
									+summaryItem(itemName)
										if (item.active)
											span.me-2
												span.text-success active
												small.text-muted.ms-2 (
													a.border-dotted(href=`./block-height/${item.height}`, title=`${itemName} has been active since block ${item.height.toLocaleString()}`, data-bs-toggle="tooltip") #{item.height.toLocaleString()}
													| +)

										else if (item.type == "bip8") || (item.type == "bip9")
											- var bip = item.type;
											- var bip_status = item[bip].status
											span.me-2
												span.text-warning.text-lowercase #{bip_status}
												small.text-muted.ms-2 (
													a.border-dotted(title=`${itemName.toUpperCase()} ${bip_status.replace("_", " ")} since block ${item[bip].since.toLocaleString()} with BIP${bip.charAt(3)} and LockinOnTimeout=${item[bip].lockinontimeout}`, data-bs-toggle="tooltip") #{item[bip].since}
													| +)

										if (forkUrls[itemName])
											small
												a(href=forkUrls[itemName], title=`More info about ${itemName}`, data-bs-toggle="tooltip", target="_blank")
													i.bi-box-arrow-up-right.small

										if (item.type == "bip9" && item.bip9 && (item.bip9.start_time || item.bip9.timeout))
											div.small.text-muted
												if (item.bip9.start_time)
													span.me-2 start:
													+timestamp(item.bip9.start_time, {includeAgo:false, formatString:"M/D"})

												if (item.bip9.timeout)
													if (item.bip9.start_time)
														span.me-1 ,
													span.me-2 timeout:
													+timestamp(item.bip9.timeout, {includeAgo:false, formatString:"M/D"})

										if (item.type == "bip9" && item.bip9 && item.bip9.min_activation_height)
											div.small.text-muted
												span.border-dotted(title="Minimum activation block height", data-bs-toggle="tooltip") min height
												span.me-2 :
												| #{item.bip9.min_activation_height.toLocaleString()}

										
										


				+contentSection("Network")
					+summaryRow(4)
						+summaryItem("Host", "IP address and port number of RPC node")
							| #{global.rpcClient.options.host}
							span.text-muted :#{global.rpcClient.options.port}

						+summaryItem("Peers", "Number of peers connected to this node.", null, null, "icon:bi-diagram-3", "./peers", "Details about the peers connected to this node")
							| #{getnetworkinfo.connections.toLocaleString()}

							if (getnetworkinfo.connections_in)
								br
								span.text-muted (#{getnetworkinfo.connections_in.toLocaleString()} in; #{getnetworkinfo.connections_out.toLocaleString()} out)

						+summaryItem("Upload", "Total bytes sent since this node started")
							- var upData = utils.formatLargeNumber(getnettotals.totalbytessent, 1);
							- var upRateData = utils.formatLargeNumber(getnettotals.totalbytessent / uptimeSeconds, 1);

							i.bi-arrow-up.me-2
							span.me-2 #{upData[0]} #{upData[1].abbreviation}B
							small.text-muted (#{upRateData[0]} #{upRateData[1].abbreviation}B/s)

						+summaryItem("Download", "Total bytes received since this node started")
							- var downData = utils.formatLargeNumber(getnettotals.totalbytesrecv, 1);
							- var downRateData = utils.formatLargeNumber(getnettotals.totalbytesrecv / uptimeSeconds, 1);
							
							i.bi-arrow-down.me-2
							span.me-2 #{downData[0]} #{downData[1].abbreviation}B
							small.text-muted (#{downRateData[0]} #{downRateData[1].abbreviation}B/s)
							
					if (getnetworkinfo.networks)
						hr.my-4

						+summaryRow(getnetworkinfo.networks.length)
							each item, index in getnetworkinfo.networks
								+summaryItem(item.name)
									div
										if (item.proxy)
											small.text-muted.me-2 (#{item.proxy})
											
										if (item.reachable)
											span.border-dotted(title="Reachable", data-bs-toggle="tooltip")
												i.bi-check2.text-success

										else
											span.border-dotted(title="Unreachable", data-bs-toggle="tooltip")
												i.bi-x.text-danger


					if (getnetworkinfo.localaddresses)
						hr.my-4

						.ms-3
							+summaryTitle("Addresses")
							.lead
								ul
									each item, index in getnetworkinfo.localaddresses
										li
											span.me-2 #{item.address}:#{item.port}
											small.text-muted (score: #{item.score.toLocaleString()})

									if (getnetworkinfo.localaddresses.length == 0)
										li None
								
							
							

			+pageTab("JSON")

				ul.nav.nav-pills.mb-3
					li.nav-item
						a.nav-link.active(data-bs-toggle="tab", href="#tab-getblockchaininfo", role="tab") getblockchaininfo
					li.nav-item
						a.nav-link(data-bs-toggle="tab", href="#tab-getnettotals", role="tab") getnettotals
					li.nav-item
						a.nav-link(data-bs-toggle="tab", href="#tab-getnetworkinfo", role="tab") getnetworkinfo
					li.nav-item
						a.nav-link(data-bs-toggle="tab", href="#tab-getindexinfo", role="tab") getindexinfo
				
				div.tab-content
					div.tab-pane.active(id="tab-getblockchaininfo", role="tabpanel")
						+contentSection("getblockchaininfo")
							pre
								code.json(data-lang="json") #{JSON.stringify(getblockchaininfo, null, 4)}
									

					div.tab-pane(id="tab-getnettotals", role="tabpanel")
						+contentSection("getnettotals")
							pre
								code.json(data-lang="json") #{JSON.stringify(getnettotals, null, 4)}
									

					div.tab-pane(id="tab-getnetworkinfo", role="tabpanel")
						+contentSection("getnetworkinfo")
							pre
								code.json(data-lang="json") #{JSON.stringify(getnetworkinfo, null, 4)}
									

					div.tab-pane(id="tab-getindexinfo", role="tabpanel")
						+contentSection("getindexinfo")
							pre
								code.json(data-lang="json") #{JSON.stringify(global.getindexinfo, null, 4)}
									
										